package com.wei.czz.framework.common.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.enums.common.exportTask.TaskTypeEnum;
import com.wei.czz.common.dto.common.exportTask.ExportTaskDto;
import com.wei.czz.common.enums.common.TaskModeEnum;
import com.wei.czz.common.enums.common.exportTask.ExportStatusEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.tool.PageQuery;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.common.vo.common.exportTask.ExportFormVo;
import com.wei.czz.framework.common.dao.ExportTaskDao;
import com.wei.czz.framework.common.entity.ExportTaskEntity;
import com.wei.czz.framework.common.service.ExportTaskService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2022-03-19 14:09:19
 * className: ExportTaskServiceImpl 系统文件导出请求服务接口实现类
 * version: 1.0
 * description:
 */
@Service("exportTaskService")
@AllArgsConstructor
public class ExportTaskServiceImpl extends ServiceImpl<ExportTaskDao, ExportTaskEntity> implements ExportTaskService {

    private static final Logger log = LoggerFactory.getLogger(ExportTaskServiceImpl.class);

    @Override
    public Long saveExportTask(ExportTaskEntity exportTask) {
        Long taskId = exportTask.getTaskId();
        if (Objects.isNull(taskId)) {
            int count = baseMapper.insert(exportTask);
            log.info("保存导出任务完成。count={}", count);
            taskId = exportTask.getTaskId();
        } else {
            int count = baseMapper.updateById(exportTask);
            log.info("修改导出任务完成。count={}", count);
        }
        return taskId;
    }

    @Override
    public ExportTaskEntity get(Long taskId) {
        ExportTaskEntity exportTask = baseMapper.selectById(taskId);
        if (Objects.isNull(exportTask)) {
            log.info("导出任务不存在");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "导出任务不存在");
        }
        if (CommonEnum.ONE.getValue().equals(exportTask.getDeleteStatus())) {
            log.info("导出任务不存在");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "导出任务不存在");
        }
        return exportTask;
    }

    @Override
    public PageDto<ExportTaskDto> getExportTaskList(ExportFormVo exportFormVo) {
        // 正在获取自己导出任务列表的用户id
        Long optUserId = SecurityUtils.getUserId();

        LambdaQueryWrapper<ExportTaskEntity> exportTaskLambdaWrapper = new LambdaQueryWrapper<>();
        // 匹配 创建用户id，任务类型、任务模式、文件类型、任务状态、删除状态和创建时间 字段
        exportTaskLambdaWrapper.eq(ExportTaskEntity::getCreateUserId, optUserId)
                .eq(Objects.nonNull(exportFormVo.getTaskType()), ExportTaskEntity::getTaskType,
                        exportFormVo.getTaskType())
                .eq(Objects.nonNull(exportFormVo.getDownloadMode()), ExportTaskEntity::getExportMode,
                        exportFormVo.getDownloadMode())
                .eq(Objects.nonNull(exportFormVo.getFileType()), ExportTaskEntity::getFileType,
                        exportFormVo.getFileType())
                .eq(Objects.nonNull(exportFormVo.getStatus()), ExportTaskEntity::getStatus, exportFormVo.getStatus())
                .ge(Objects.nonNull(exportFormVo.getCreateTime1()), ExportTaskEntity::getCreateTime,
                        exportFormVo.getCreateTime1())
                .le(Objects.nonNull(exportFormVo.getCreateTime2()), ExportTaskEntity::getCreateTime,
                        exportFormVo.getCreateTime2());
        // 构造mp分页对象
        Page<ExportTaskEntity> page = PageQuery.initPage(exportFormVo);
        // 查询数据库
        this.page(page, exportTaskLambdaWrapper);

        List<ExportTaskEntity> exportTaskList = page.getRecords();
        List<ExportTaskDto> exportTaskDtoList = new ArrayList<>(exportTaskList.size());
        for (ExportTaskEntity exportTask : exportTaskList) {
            ExportTaskDto exportTaskDto = new ExportTaskDto();
            // 属性值复制
            BeanUtils.copyProperties(exportTask, exportTaskDto);
            // 设置任务类型名称
            exportTaskDto.setTaskId(exportTask.getTaskId().toString())
                        .setTaskTypeName(TaskTypeEnum.findName(exportTask.getTaskType()));

            exportTaskDtoList.add(exportTaskDto);
        }
        // 返回结果封装
        return new PageDto<>(exportTaskDtoList, page.getTotal(), exportFormVo.getPage(), exportFormVo.getLimit());
    }

    @Override
    public void downloadFile(Long taskId, HttpServletRequest request, HttpServletResponse response) {

        ExportTaskEntity exportTask = baseMapper.selectById(taskId);
        if (Objects.isNull(exportTask)) {
            log.error("导出任务为空，结束下载");
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "任务不存在，请确认");
        }
        if (exportTask.getExportMode().equals(TaskModeEnum.SYNC.getValue())) {
            // 任务模式为同步
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您已经下载过文件，请勿重复下载。");
        }
        if (!exportTask.getStatus().equals(ExportStatusEnum.SUCCESS.getValue())) {
            // 导出状态不是成功状态
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "导出任务没有执行成功，请确认，如有问题，请联系管理员处理。");
        }
        if (exportTask.getDeleteStatus().equals(CommonEnum.ONE.getValue())) {
            // 导出任务被删除
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "导出任务已被删除，下载失败，如有问题，请联系管理员处理。");
        }
        // 获取正在下载自己任务文件的用户id
        Long optUserId = SecurityUtils.getUserId();
        if (!optUserId.equals(exportTask.getCreateUserId())) {
            // 导出任务不属于当前操作用户
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "导出任务不属于您，下载失败，如有问题，请联系管理员处理。");
        }

        String filePath = exportTask.getFilePath();
        if (StringUtils.isBlank(filePath)) {
            log.error("下载文件存储路径为空");
            throw new CzzException();
        }
        File file = new File(filePath);
        if(!file.exists()) {
            log.error("导出文件不存在，请务必及时处理。filePath={}", filePath);
            //文件不存在
            throw new CzzException();
        }
        // 获取文件名
        String fileName = file.getName();
        log.info("下载文件名={}", fileName);

        // 创建输出流
        OutputStream fos;
        try {
            fos = response.getOutputStream();
        } catch (IOException e) {
            log.error("获取响应结果输出流异常。message={}", e.getMessage(), e);
            throw new CzzException();
        }

        try (InputStream fis = Files.newInputStream(file.toPath())) {

            response.reset();
            // 客户端显示返回结果头数据
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            // 允许返回结果跨域
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
            // 设置返回结果编码格式
            response.setCharacterEncoding("utf-8");
            // 设置响应头，控制浏览器下载该文件
            response.setHeader("content-disposition", "attachment;filename=" +
                    URLEncoder.encode(fileName, StandardCharsets.UTF_8));
            response.setContentType("application/octet-stream");

            // 缓存字节数组
            byte[] buffer = new byte[1024];
            // 判断输入流中的数据是否已经读完的标识
            int len;
            while((len = fis.read(buffer)) > 0){
                fos.write(buffer, 0, len);
            }
            // 最后执行一次推送数据操作
            fos.flush();
        } catch (IOException e) {
            log.error("下载的文件写入输出流异常。message={}", e.getMessage(), e);
            throw new CzzException("文件下载失败，请务必及时处理");
        }
    }

    @Override
    public void deleteExportTask(List<Long> taskIdList) {

        LambdaUpdateWrapper<ExportTaskEntity> exportTaskLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置 删除标记（‘删除’） 字段值
        exportTaskLambdaUpdateWrapper.set(ExportTaskEntity::getDeleteStatus, CommonEnum.ONE.getValue());
        // 匹配 导出任务主键 字段
        exportTaskLambdaUpdateWrapper.in(ExportTaskEntity::getTaskId, taskIdList)
                .eq(ExportTaskEntity::getDeleteStatus, CommonEnum.ZERO.getValue());

        int count = baseMapper.update(null, exportTaskLambdaUpdateWrapper);
        log.info("批量删除导出任务完成。count={}", count);
    }

}